package com.hxzy.common.util;

import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import com.hxzy.common.constans.RedisConstans;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.vo.R;
import com.hxzy.dto.RecruitSmsDTO;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.Region;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 腾讯云短信发送工具
 * https://cloud.tencent.com/document/product/382/43194
 * @author Administrator
 */
@Log4j2
@Component
public class TencentSmsUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String secretId="AKIDrSmZ6M199sOedNa2wyjCOIo3nKcdgowp";
    private static final String secretKey="lHVsymIX2HFxNYR6UcT7UbS2PWS8gFhu";

    /**
     * 发送短信（商家注册）
     * @param phone
     * @return
     */
    public   R sendSMS(String phone) {

        try {
            /* 必要步骤：
             * 实例化一个认证对象，入参需要传入腾讯云账户密钥对secretId，secretKey。
             * 这里采用的是从环境变量读取的方式，需要在环境变量中先设置这两个值。
             * 你也可以直接在代码中写死密钥对，但是小心不要将代码复制、上传或者分享给他人，
             * 以免泄露密钥对危及你的财产安全。
             * SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */
            Credential cred = new Credential(secretId, secretKey);

            /* 非必要步骤:
             * 实例化一个客户端配置对象，可以指定超时时间等配置 */
            ClientProfile clientProfile = new ClientProfile();

            /* 实例化要请求产品(以sms为例)的client对象
             * 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
            SmsClient client = new SmsClient(cred, Region.Guangzhou.getValue(),clientProfile);
            /* 实例化一个请求对象，根据调用的接口和实际情况，可以进一步设置请求参数
             * 你可以直接查询SDK源码确定接口有哪些属性可以设置
             * 属性可能是基本类型，也可能引用了另一个数据结构
             * 推荐使用IDE进行开发，可以方便的跳转查阅各个接口和数据结构的文档说明 */
            SendSmsRequest req = new SendSmsRequest();

            /* 填充请求参数,这里request对象的成员变量即对应接口的入参
             * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
             * 基本类型的设置:
             * 帮助链接：
             * 短信控制台: https://console.cloud.tencent.com/smsv2
             * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */

            /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId，示例如1400006666 */
            // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
            String sdkAppId = "1400412221";
            req.setSmsSdkAppId(sdkAppId);

            /* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名 */
            // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
            String signName = "易发公众号";
            req.setSignName(signName);

            /* 模板 ID: 必须填写已审核通过的模板 ID */
            // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
            //{1}为您的登录验证码，请于{2}分钟内填写，如非本人操作，请忽略本短信。
            String templateId = "1451707";
            req.setTemplateId(templateId);

            /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致，若无模板参数，则设置为空 */
            Random  rd=new Random();
            //4位数 (1000~9999)     [0-8999]
            String code= (rd.nextInt(9000)+1000)+"";

            String[] templateParamSet = {code, RedisConstans.SMS_EXPIRED_MINUTES+""};
            req.setTemplateParamSet(templateParamSet);

            /* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
             * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号 */
            String[] phoneNumberSet = {"+86"+phone };
            req.setPhoneNumberSet(phoneNumberSet);

            /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
             * 返回的 res 是一个 SendSmsResponse 类的实例，与请求对象对应 */
            SendSmsResponse res = client.SendSms(req);

            // 输出json格式的字符串回包
            log.info(SendSmsResponse.toJsonString(res));

            //写入到redis中
            String uuid= SecureUtil.md5(phone) ;
            String redisKey=RedisConstans.getRedisKey(RedisConstans.SMS_KEY,uuid);
            this.redisTemplate.opsForValue().set(redisKey,code,RedisConstans.SMS_EXPIRED_MINUTES, TimeUnit.MINUTES);
            //封装map
            Map<String,Object> data=new HashMap<String,Object>();
            data.put("uuid", uuid);
            data.put("expired_minutes",RedisConstans.SMS_EXPIRED_MINUTES*60);
            return R.okHasData(data);
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            return R.build(AckCode.SMS_SEND_ERROR);
        }
    }

    /**
     * 发送短信通知商家申核通过短信
     * @param phone
     * @return
     */
    public   R sendMerchandiserPass(String phone) {

        try {
            /* 必要步骤：
             * 实例化一个认证对象，入参需要传入腾讯云账户密钥对secretId，secretKey。
             * 这里采用的是从环境变量读取的方式，需要在环境变量中先设置这两个值。
             * 你也可以直接在代码中写死密钥对，但是小心不要将代码复制、上传或者分享给他人，
             * 以免泄露密钥对危及你的财产安全。
             * SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */
            Credential cred = new Credential(secretId, secretKey);

            /* 非必要步骤:
             * 实例化一个客户端配置对象，可以指定超时时间等配置 */
            ClientProfile clientProfile = new ClientProfile();

            /* 实例化要请求产品(以sms为例)的client对象
             * 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
            SmsClient client = new SmsClient(cred, Region.Guangzhou.getValue(),clientProfile);
            /* 实例化一个请求对象，根据调用的接口和实际情况，可以进一步设置请求参数
             * 你可以直接查询SDK源码确定接口有哪些属性可以设置
             * 属性可能是基本类型，也可能引用了另一个数据结构
             * 推荐使用IDE进行开发，可以方便的跳转查阅各个接口和数据结构的文档说明 */
            SendSmsRequest req = new SendSmsRequest();

            /* 填充请求参数,这里request对象的成员变量即对应接口的入参
             * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
             * 基本类型的设置:
             * 帮助链接：
             * 短信控制台: https://console.cloud.tencent.com/smsv2
             * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */

            /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId，示例如1400006666 */
            // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
            String sdkAppId = "1400412221";
            req.setSmsSdkAppId(sdkAppId);

            /* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名 */
            // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
            String signName = "易发公众号";
            req.setSignName(signName);

            /* 模板 ID: 必须填写已审核通过的模板 ID */
            // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
            //{1}为您的登录验证码，请于{2}分钟内填写，如非本人操作，请忽略本短信。
            String templateId = "1451814";
            req.setTemplateId(templateId);

            /* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
             * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号 */
            String[] phoneNumberSet = {"+86"+phone };
            req.setPhoneNumberSet(phoneNumberSet);

            /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
             * 返回的 res 是一个 SendSmsResponse 类的实例，与请求对象对应 */
            SendSmsResponse res = client.SendSms(req);

            // 输出json格式的字符串回包
            log.info(SendSmsResponse.toJsonString(res));

            return R.ok();
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            return R.build(AckCode.SMS_SEND_ERROR);
        }
    }

    /**
     * 发送短信（模拟发短信测试，不会调用腾讯云）
     * @param phone
     * @return
     */
    public   R sendSMSImitate(String phone) {
        /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致，若无模板参数，则设置为空 */
        Random rd = new Random();
        //4位数 (1000~9999)     [0-8999]
        String code = (rd.nextInt(9000) + 1000) + "";
        //写入到redis中
        String uuid= SecureUtil.md5(phone) ;
        String redisKey = RedisConstans.getRedisKey(RedisConstans.SMS_KEY, uuid);
        this.redisTemplate.opsForValue().set(redisKey, code, RedisConstans.SMS_EXPIRED_MINUTES, TimeUnit.MINUTES);
        //封装map
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("uuid", uuid);
        data.put("expired_minutes", RedisConstans.SMS_EXPIRED_MINUTES * 60);
        return R.okHasData(data);
    }

    /**
     * 验证redis中是否存在值
     * @return
     */
    public boolean redisExistsValue(String redisKey){
         return this.redisTemplate.hasKey(redisKey);
    }

    /**
     * 验证注册码对不对
     * @param recruitSmsDTO
     * @return
     */
    public R recruieValidate(RecruitSmsDTO recruitSmsDTO){
        //判断是不是原来注册手机号
        String md5= SecureUtil.md5(recruitSmsDTO.getLoginName());
        if(!md5.equals(recruitSmsDTO.getUuid())){
            return R.build(AckCode.SMS_MOBILE_ERROR);
        }
        //验证redis的值是否正确
        String redisKey = RedisConstans.getRedisKey(RedisConstans.SMS_KEY, recruitSmsDTO.getUuid());
        Object redisValue=this.redisTemplate.opsForValue().get(redisKey);
        if(redisValue==null){
           return R.build(AckCode.SMS_CODE_OVERTIME);
        }

        //判断是否正确
        if(!redisValue.toString().equals(recruitSmsDTO.getCode())){
            return  R.build(AckCode.SMS_CODE_WRONG);
        }

        //移出验证
        this.redisTemplate.delete(redisKey);

        return R.ok();
    }
}
